/*
 ============================================================================
 Name        : tarea1.c
 Author      : Carlos Alegría
 Version     :
 Copyright   : 
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "punto.h"
#include "poligono_regular.h"
#include "poligono_monotono.h"

#define PR_POSICION_X      10
#define PR_POSICION_Y      20
#define PR_LADOS           5
#define PR_RADIO           1.5f
#define PR_PERIMETRO       8.81677878439f
#define PR_AREA            5.34969290f

#define PM_PERIMETRO    14.7792717444f
#define PM_AREA         11.5f

#define RANGO           0.01f

/**
 *
 */
void
probar_obtener_posicion(poligono_regular *, punto *);

/**
 *
 */
void
limipiar_vertices(punto **, int);

/**
 *
 */
int
main(void)
{
  //
  // probando código de la estrucura punto
  //


  printf("Probando punto ...\n");

  punto *p1 = crear_punto(PR_POSICION_X, PR_POSICION_Y);
  punto *p2 = crear_punto(PR_POSICION_X, PR_POSICION_Y);

  assert( p1->x == PR_POSICION_X && p1->y == PR_POSICION_Y);
  assert( p1 != p2);
  assert( comparar(p1, p2));

  printf("ok\n");


  //
  // probando código de la estrucura poligono_regular
  //


  printf("Probando polígono regular ...\n");

  // punto nulo
  //
  assert( pr_crear_poligono(NULL, 4, 1) == NULL);

  // menos de tres vertices
  //
  assert( pr_crear_poligono(p1, 2, 1) == NULL);

  // radio no positivo
  //
  assert( pr_crear_poligono(p1, 4, -1) == NULL);

  // obtener posicion
  //
  poligono_regular *pr_poligono = pr_crear_poligono(p1, PR_LADOS, PR_RADIO);
  probar_obtener_posicion(pr_poligono, p1);

  // cambiar posición
  //
  punto *p3 = crear_punto(0, 0);
  pr_cambiar_posicion(pr_poligono, p3);
  probar_obtener_posicion(pr_poligono, p3);

  // lados, radio, perimetro, area
  //
  assert(pr_poligono->lados == PR_LADOS);
  assert(pr_poligono->radio == PR_RADIO);
  assert(abs(pr_poligono->perimetro - PR_PERIMETRO) <= RANGO);
  assert(abs(pr_poligono->area - PR_AREA) <= RANGO);

  printf("ok\n");


  //
  // probando código de la estrucura poligono_monotono
  //

  printf("Probando polígono monótono ...\n");

  // arreglo nulo
  //
  assert( pm_crear_poligono( NULL, 0) == NULL);

  // menos de tres vértices
  //
  assert( pm_crear_poligono( (punto **) 20, 2) == NULL);

  // arreglo válido, vértices nulos
  //
  punto **vertices = (punto **) malloc(sizeof(punto *) * 4);
  vertices[0] = crear_punto(1, 3);
  vertices[1] = NULL;
  vertices[2] = crear_punto(1, 3);
  vertices[3] = NULL;
  assert(pm_crear_poligono(vertices, 4) == NULL);
  limipiar_vertices(vertices, 4);

  // vertices no monótonos
  //
  vertices = (punto **) malloc(sizeof(punto *) * 5);
  vertices[0] = crear_punto(1, 1);
  vertices[1] = crear_punto(2, 2);
  vertices[2] = crear_punto(3, -1);
  vertices[3] = crear_punto(2, 0);
  vertices[4] = crear_punto(3, -2);
  assert(pm_crear_poligono(vertices, 5) == NULL);
  limipiar_vertices(vertices, 5);

  // polígono válido
  //
  vertices = (punto **) malloc(sizeof(punto *) * 8);
  vertices[0] = crear_punto(1, 3);
  vertices[1] = crear_punto(2, 4);
  vertices[2] = crear_punto(4, 3);
  vertices[3] = crear_punto(5, 4);
  vertices[4] = crear_punto(6, 2);
  vertices[5] = crear_punto(4, 0);
  vertices[6] = crear_punto(3, 1);
  vertices[7] = crear_punto(2, 1);
  poligono_monotono *pm_poligono = pm_crear_poligono(vertices, 8);
  assert(pm_poligono != NULL);

  // perimetro y area
  //
  assert(abs(pm_poligono->perimetro - PM_PERIMETRO) <= RANGO);
  assert(abs(pm_poligono->area - PM_AREA) <= RANGO);

  // obtener posición
  //
  assert(comparar(pm_obtener_posicion(pm_poligono), vertices[0]));

  // cambiar posicion
  //
  punto *p5 = crear_punto(7, 8);
  pm_cambiar_posicion(pm_poligono, p5);

  assert(vertices[0]->x == 7);
  assert(vertices[0]->y == 8);
  assert(vertices[1]->x == 8);
  assert(vertices[1]->y == 9);
  assert(vertices[2]->x == 10);
  assert(vertices[2]->y == 8);
  assert(vertices[3]->x == 11);
  assert(vertices[3]->y == 9);
  assert(vertices[4]->x == 12);
  assert(vertices[4]->y == 7);
  assert(vertices[5]->x == 10);
  assert(vertices[5]->y == 5);
  assert(vertices[6]->x == 9);
  assert(vertices[6]->y == 6);
  assert(vertices[7]->x == 8);
  assert(vertices[7]->y == 6);

  free(pm_poligono);
  free(pr_poligono);
  free(p1);
  free(p2);
  free(p3);
  free(p5);

  printf("ok\n");

  return EXIT_SUCCESS;
}

/**
 *
 */
void
probar_obtener_posicion(poligono_regular *poligono, punto *posicion)
{
  assert( comparar(pr_obtener_posicion(poligono), posicion));
}

/**
 *
 */
void
limipiar_vertices(punto **vertices, int n)
{
  int i = 0;
  for (i = 0; i < n; i++)
    {
      free(vertices[i]);
    }

  free(vertices);
}
